package com.iwhalecloud.bss.kite.cucc.order.accept.chain.impl;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.iwhalecloud.bss.kite.common.constant.TableConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.cucc.order.accept.chain.AbstractOrderHandler;
import com.iwhalecloud.bss.kite.cucc.order.accept.constructor.DataConstructorFactory;
import com.iwhalecloud.bss.kite.cucc.order.accept.constructor.IDataConstructor;
import com.iwhalecloud.bss.kite.cucc.order.accept.constructor.inst.InstConstructor;
import com.iwhalecloud.bss.kite.cucc.order.accept.constructor.inst.RelConstructor;
import com.iwhalecloud.bss.kite.cucc.order.loader.IInstLoader;
import com.iwhalecloud.bss.kite.cucc.order.loader.InstLoaderFactory;
import com.iwhalecloud.bss.kite.cucc.order.util.AcceptUtils;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferCache;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.IInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.OfferInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.OfferObjInstRel;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.OfferProdInstRel;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.ProdInst;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Offer;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.OfferDetail;
import com.iwhalecloud.bss.kite.dataservice.mapper.inst.OfferProdInstRelMapper;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstRelDTO;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteMktResInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstAcct;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstAssure;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInstAcct;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInstFunc;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInstState;
import com.iwhalecloud.bss.kite.manager.inst.KiteSubProdInst;
import com.iwhalecloud.bss.kite.manager.inst.change.KiteInstChange;
import com.iwhalecloud.bss.kite.manager.inst.graph.IRelType;
import com.iwhalecloud.bss.kite.manager.inst.graph.impl.RelEdge;
import com.iwhalecloud.bss.kite.manager.util.InstTypeUtils;
import com.iwhalecloud.bss.kite.manager.util.ManagerUtils;
import com.iwhalecloud.bss.kite.manager.util.RelTypeUtils;
import com.iwhalecloud.bss.kite.order.client.dto.InstContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequest;
import com.iwhalecloud.bss.kite.order.client.proxy.InstContainerProxy;
import com.ztesoft.bss.base.staticdata.CoreDataOffer;
import com.ztesoft.bss.base.staticdata.CoreDataPublic;
import com.ztesoft.bss.common.util.SpringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 订单受理流程：实例拆机/退订处理
 */
@Component
public class DismantleHandler extends AbstractOrderHandler {

    @Resource
    private IQuerySceneInstService querySceneInstService;

    @Override
    public void doHandle(OrderRequest orderRequest) {
        InstContainerProxy instContainer = InstContainer.ofRequest(orderRequest);
        dismantleOfferInsts(orderRequest, instContainer.listOfferInsts());
        dismantleProdInsts(orderRequest, instContainer.listProdInsts());
    }

    /**
     * 销售品实例退订，只处理actionType=D的销售品实例
     * @param orderRequest
     * @param offerInsts
     */
    private void dismantleOfferInsts(OrderRequest orderRequest, List<OfferInst> offerInsts) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(offerInsts)) {
            return;
        }

        for (OfferInst offerInst : offerInsts) {
            if (!Objects.equals(ActionType.D.name(), offerInst.getActionType())) {
                continue;
            }

            String offerType = offerInst.getOfferType();
            if (Objects.equals(CoreDataOffer.OFF_0005_10, offerType)) {
                dismantleBaseOfferInst(orderRequest, offerInst);
            }
            else {
                dismantleOfferInst(orderRequest, offerInst);
            }
        }
    }

    /**
     * 销售品实例退订，如果销售品实例的actionType不为D，则强行退订此销售品，同时处理销售品实例的上下级实例
     * @param orderRequest
     * @param offerInst
     */
    private void dismantleOfferInst(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)) {
            return;
        }

        String custId = offerInst.getOwnerCustId();
        String offerInstId = offerInst.getOfferInstId();
        // 退订销售品实例
        if (!Objects.equals(ActionType.D.name(), offerInst.getActionType())) {
            InstConstructor.dismantleInst(orderRequest, offerInst,
                AcceptUtils.getOfferInstType(offerInst.getOfferType()), offerInstId, null, null);
        }

        // 销售品实例和接入产品实例、账户级销售品实例的关系
        List<KiteInstRelDTO> offerObjInstRels = querySceneInstService.listInstRelsByAInst(custId,
            InstTypeUtils.listOfferInstTypes(), offerInstId,
            Lists.newArrayList(InstType.PROD_INST, InstType.OFFER_INST_ACCT));
        dismantleInstRels(orderRequest, offerObjInstRels, TableConsts.OfferObjInstRel.getTableName(),
            RelType.OFFER_OBJ_REL_TYPE, custId);

        // 销售品实例和功能产品实例关系
        List<KiteInstRelDTO> offerProdInstRels = querySceneInstService.listInstRelsByAInst(custId,
            InstTypeUtils.listOfferInstTypes(), offerInstId, InstType.PROD_INST_FUNC);
        dismantleInstRels(orderRequest, offerProdInstRels, TableConsts.OfferProdInstRel.getTableName(),
            RelType.OFFER_PROD_REL_TYPE, custId);

        if (!(Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())
            || Objects.equals(CoreDataOffer.OFF_0005_10, offerInst.getOfferType()))) {
            // 退订销售品实例的下级可选包销售品实例
            List<KiteOfferInst> additionalOfferInsts = querySceneInstService
                .listAdditionalOfferInstsFromOfferInst(custId, offerInstId);
            dismantleAdditionalOfferInsts(orderRequest, additionalOfferInsts, custId,
                AcceptUtils.getOfferInstType(offerInst.getOfferType()), offerInst.getOfferInstId());
        }
        else if (Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())) {
            // 如果是可选包删除，则上级主套餐或促销销售品实例产生修改变动
            modifyParentOfferInstByAdditionalOfferInst(orderRequest, offerInst);
        }
    }

    /**
     * 退订可选包销售品实例
     * @param orderRequest
     * @param additionalOfferInsts
     * @param custId
     * @param parentInstType
     * @param parentInstId
     */
    private void dismantleAdditionalOfferInsts(OrderRequest orderRequest, List<KiteOfferInst> additionalOfferInsts,
        String custId, InstType parentInstType, String parentInstId) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(additionalOfferInsts)) {
            return;
        }

        for (KiteOfferInst kiteOfferInst : additionalOfferInsts) {
            if (!Objects.equals(InstType.ADDITIONAL_OFFER_INST, kiteOfferInst.getInstType())) {
                continue;
            }

            String tableName = TableConsts.OfferInst.getTableName();
            IInstLoader<OfferInst> instLoader = InstLoaderFactory.getInstLoader(TableConsts.OfferInst.getTableName());
            OfferInst offerInst = instLoader.loadInst(orderRequest, tableName, kiteOfferInst.getInstId(), custId);
            String newCompInstId = getAdditionalOfferInstNewCompInstId(orderRequest, custId,
                kiteOfferInst.getOfferInstId(), parentInstType, parentInstId);
            // 如果可选包销售品实例有一条A的关系，不退订，修改compInstId
            if (StringUtils.isBlank(newCompInstId) || Objects.equals(ActionType.D.name(), offerInst.getActionType())) {
                dismantleOfferInst(orderRequest, offerInst);
            }
            else {
                // 修改可选包销售品实例和明细实例的compInstId
                updateAdditionalOfferInstCompInstId(orderRequest, offerInst, newCompInstId);
            }
        }
    }

    /**
     * 如果是签转，获取可选包销售品实例新的上级实例的compInstId
     * @param orderRequest
     * @param custId
     * @param offerInstId
     * @param parentInstType
     * @param parentInstId
     * @return
     */
    private String getAdditionalOfferInstNewCompInstId(OrderRequest orderRequest, String custId, String offerInstId,
        InstType parentInstType, String parentInstId) {
        List<InstType> aInsttTypes = Lists.newArrayList(InstType.MAIN_OFFER_INST, InstType.PROD_INST,
            InstType.PROMOTION_OFFER_INST);
        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(custId,
            InstType.ADDITIONAL_OFFER_INST, offerInstId, aInsttTypes);
        // 如果是签转，可选包销售品实例可能会有两条上级关系(与旧套餐销售品实例D的关系和新套餐销售品实例A的关系)
        KiteInstRelDTO instRel = instRels.stream().filter(rel -> {
            return !(Objects.equals(parentInstType, rel.getaInstType())
                && Objects.equals(parentInstId, rel.getaInstId())) && Objects.equals(ActionType.A, rel.getActionType());
        }).sorted((o1, o2) -> {
            InstType instType1 = o1.getaInstType();
            InstType instType2 = o2.getaInstType();

            if (!ObjectUtils.allNotNull(instType1, instType2)) {
                // 不交换顺序
                return 0;
            }
            if (Objects.isNull(instType1)) {
                // 交换顺序，空值排后面
                return 1;
            }
            if (Objects.isNull(instType2)) {
                // 不交换顺序，空值排后面
                return -1;
            }

            int index1 = aInsttTypes.indexOf(instType1);
            int index2 = aInsttTypes.indexOf(instType2);
            // index小的排前面
            return index1 - index2;
        }).findFirst().orElse(null);

        if (Objects.nonNull(instRel)) {
            if (AcceptUtils.isOfferInst(instRel.getaInstType())) {
                OfferInst offerInst = InstContainer.ofRequest(orderRequest).getOfferInst(instRel.getaInstId());
                if (Objects.nonNull(offerInst) && !Objects.equals(ActionType.D.name(), offerInst.getActionType())) {
                    return offerInst.getOfferInstId();
                }
            }
            else if (Objects.equals(InstType.PROD_INST, instRel.getaInstType())) {
                ProdInst prodInst = InstContainer.ofRequest(orderRequest).getProdInst(instRel.getaInstId());
                if (Objects.nonNull(prodInst) && !Objects.equals(ActionType.D.name(), prodInst.getActionType())) {
                    return prodInst.getCompInstId();
                }
            }
        }

        return "";
    }

    /**
     * 可选包换套餐，更新可选包销售品实例和明细关系的compInstId(只有可选包可以更新compInstId)
     * @param orderRequest
     * @param offerInst
     * @param newCompInstId
     */
    private void updateAdditionalOfferInstCompInstId(OrderRequest orderRequest, OfferInst offerInst,
        String newCompInstId) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)
            || !Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())
            || Objects.equals(ActionType.D.name(), offerInst.getActionType()) || StringUtils.isBlank(newCompInstId)
            || Objects.equals(newCompInstId, offerInst.getCompInstId())) {
            return;
        }

        String oldCompInstId = offerInst.getCompInstId();
        offerInst.setCompInstId(newCompInstId);
        if (StringUtils.equalsAny(offerInst.getActionType(), ActionType.A.name(), ActionType.K.name())) {
            offerInst.setActionType(ActionType.M.name());
        }

        // 补充实例comp_inst_id的变动信息
        AcceptUtils.addInstChange(orderRequest, offerInst.getOfferInstId(), InstType.ADDITIONAL_OFFER_INST,
            ActionType.M, "comp_inst_id", oldCompInstId, newCompInstId);

        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByAInst(offerInst.getOwnerCustId(),
            InstType.ADDITIONAL_OFFER_INST, offerInst.getOfferInstId(), InstType.PROD_INST);
        // 更新明细关系的compInstId
        updateOfferObjInstRelCompInstId(orderRequest, instRels, newCompInstId);
    }

    /**
     * 更新销售品包含对象实例的compInstId
     * @param orderRequest
     * @param instRels
     * @param newCompInstId
     */
    private void updateOfferObjInstRelCompInstId(OrderRequest orderRequest, List<KiteInstRelDTO> instRels,
        String newCompInstId) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(instRels) || StringUtils.isBlank(newCompInstId)) {
            return;
        }

        RelConstructor<OfferObjInstRel> dataConstructor = DataConstructorFactory
            .getRelConstructor(RelType.OFFER_OBJ_REL_TYPE);
        for (KiteInstRelDTO instRel : instRels) {
            String type = Optional.ofNullable(instRel.getRelType()).map(IRelType::getType).orElse("");
            String code = Optional.ofNullable(instRel.getRelType()).map(IRelType::getCode).orElse("");
            if (!Objects.equals(RelType.OFFER_OBJ_REL_TYPE, type)
                || Objects.equals(ActionType.D, instRel.getActionType())) {
                continue;
            }

            OfferObjInstRel offerObjInstRel = null;
            if (!dataConstructor.contains(orderRequest, instRel.getaInstId(), instRel.getzInstId(),
                ImmutableMap.of(IDataConstructor.KEY_REL_TYPE, code))) {
                RelEdge relEdge = KiteBeanUtils.transform(instRel, RelEdge.class);
                relEdge.setSourceInstId(instRel.getaInstId());
                relEdge.setSourceInstType(instRel.getaInstType());
                relEdge.setTargetInstId(instRel.getzInstId());
                relEdge.setTargetInstType(instRel.getzInstType());
                offerObjInstRel = dataConstructor.build(orderRequest, relEdge, null);
            }
            else {
                offerObjInstRel = InstContainer.ofRequest(orderRequest).getOfferObjInstRel(instRel.getaInstId(),
                    instRel.getzInstId(), code);
            }

            if (Objects.isNull(offerObjInstRel) || Objects.equals(ActionType.D.name(), offerObjInstRel.getActionType())
                || Objects.equals(newCompInstId, offerObjInstRel.getCompInstId())) {
                continue;
            }

            String oldCompInstId = offerObjInstRel.getCompInstId();
            offerObjInstRel.setCompInstId(newCompInstId);
            if (StringUtils.equalsAny(offerObjInstRel.getActionType(), ActionType.A.name(), ActionType.K.name())) {
                offerObjInstRel.setActionType(ActionType.M.name());
            }

            // 补充关系comp_inst_id的变动信息
            AcceptUtils.addRelChange(orderRequest, instRel.getaInstId(), instRel.getaInstType(), instRel.getzInstId(),
                instRel.getzInstType(), instRel.getRelType(), "comp_inst_id", oldCompInstId, newCompInstId);
        }
    }

    /**
     * 联动把可选包销售品实例的上级销售品实例的actionType改为M
     * @param orderRequest
     * @param offerInst
     */
    private void modifyParentOfferInstByAdditionalOfferInst(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)
            || !Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())) {
            return;
        }

        String custId = offerInst.getOwnerCustId();
        String offerInstId = offerInst.getOfferInstId();
        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(custId,
            InstType.ADDITIONAL_OFFER_INST, offerInstId,
            Lists.newArrayList(InstType.MAIN_OFFER_INST, InstType.PROMOTION_OFFER_INST, InstType.PROD_INST));

        for (KiteInstRelDTO instRel : instRels) {
            OfferInst parentOfferInst = getParentOfferInst(orderRequest, instRel);
            if (Objects.nonNull(parentOfferInst)
                && StringUtils.equalsAny(parentOfferInst.getActionType(), ActionType.A.name(), ActionType.K.name())) {
                AcceptUtils.setActionType(parentOfferInst, ActionType.M.name());
            }
        }
    }

    /**
     * 获取父级销售品实例
     * @param orderRequest
     * @param instRel
     * @return
     */
    private OfferInst getParentOfferInst(OrderRequest orderRequest, KiteInstRelDTO instRel) {
        if (!ObjectUtils.allNotNull(orderRequest, instRel)) {
            return null;
        }

        // 加载实例对象
        String aInstId = instRel.getaInstId();
        InstType aInstType = instRel.getaInstType();
        IDataConstructor<String, IInst> dataConstructor = DataConstructorFactory
            .getInstConstructor(instRel.getaInstType());
        if (!dataConstructor.contains(orderRequest, "", aInstId, null)) {
            dataConstructor.build(orderRequest, aInstId, null);
        }

        OfferInst offerInst = null;
        if (Objects.equals(InstType.PROD_INST, instRel.getaInstType())) {
            ProdInst prodInst = InstContainer.ofRequest(orderRequest).getInst(TableConsts.ProdInst.getTableName(),
                aInstId);
            if (Objects.nonNull(prodInst)) {
                // 获取基础销售品实例
                offerInst = InstContainer.ofRequest(orderRequest).getInst(TableConsts.OfferInst.getTableName(),
                    prodInst.getCompInstId());
            }
        }
        else if (AcceptUtils.isOfferInst(aInstType)) {
            offerInst = InstContainer.ofRequest(orderRequest).getInst(TableConsts.OfferInst.getTableName(), aInstId);
        }

        return offerInst;
    }

    /**
     * 接入产品实例拆机
     * @param orderRequest
     * @param prodInsts
     */
    private void dismantleProdInsts(OrderRequest orderRequest, List<ProdInst> prodInsts) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(prodInsts)) {
            return;
        }

        for (ProdInst prodInst : prodInsts) {
            if (!Objects.equals(ActionType.D.name(), prodInst.getActionType())) {
                continue;
            }

            String custId = prodInst.getOwnerCustId();
            String prodInstId = prodInst.getProdInstId();
            // 功能产品实例
            List<KiteProdInstFunc> prodInstFuncs = querySceneInstService.listProdInstFuncs(custId, prodInstId);
            dismantleInsts(orderRequest, prodInst, prodInstFuncs, TableConsts.ProdInstFunc.getTableName());

            // 终端实例
            List<KiteMktResInst> mktResInsts = querySceneInstService.listMktResInstsByProdInstId(custId,
                prodInstId);
            dismantleInsts(orderRequest, prodInst, mktResInsts, TableConsts.OfferResInstRelExt.getTableName());

            // 账户实例
            List<KiteProdInstAcct> prodInstAccts = querySceneInstService.listProdInstAccts(custId, prodInstId);
            dismantleInsts(orderRequest, prodInst, prodInstAccts, TableConsts.ProdInstAcctRel.getTableName());

            // 停机记录
            List<KiteProdInstState> prodInstStates = querySceneInstService.listProdInstStates(custId, prodInstId);
            dismantleInsts(orderRequest, prodInst, prodInstStates, TableConsts.ProdInstState.getTableName());

            // 担保信息
            List<KiteOfferInstAssure> offerInstAssures = querySceneInstService.listOfferInstAssures(custId,
                prodInstId);
            dismantleInsts(orderRequest, prodInst, offerInstAssures, TableConsts.OfferInstAssureExt.getTableName());

            // 子产品实例
            List<KiteSubProdInst> subProdInsts = querySceneInstService.listSubProdInsts(custId, prodInstId);
            dismantleInsts(orderRequest, prodInst, subProdInsts, TableConsts.SubProdInst.getTableName());

            // 产品实例关系
            List<KiteInstRelDTO> prodInstRels = new ArrayList<>();
            prodInstRels.addAll(
                querySceneInstService.listInstRelsByAInst(custId, InstType.PROD_INST, prodInstId, InstType.PROD_INST));

            // 功能产品实例和接入产品实例群组关系(A端是功能产品实例，Z端是接入产品实例)
            for (KiteProdInstFunc prodInstFunc : prodInstFuncs) {
                if (!AcceptUtils.isGroupProdInstFunc(prodInstFunc)) {
                    continue;
                }
                prodInstRels.addAll(querySceneInstService.listInstRelsByAInst(custId, prodInstFunc.getInstType(),
                    prodInstFunc.getProdInstId(), InstType.PROD_INST));
            }

            dismantleInstRels(orderRequest, prodInstRels, TableConsts.ProdInstRel.getTableName(), RelType.PROD_REL_TYPE,
                custId);

            prodInstRels.clear();
            prodInstRels.addAll(querySceneInstService.listInstRelsByZInst(custId, InstType.PROD_INST, prodInstId,
                Lists.newArrayList(InstType.PROD_INST, InstType.PROD_INST_FUNC)));
            // 产品实例关系的客户id是A端的产品实例的客户id，接入产品实例做为Z端时，产品实例关系的客户id不一定跟Z端接入产品实例的一样
            dismantleInstRels(orderRequest, prodInstRels, TableConsts.ProdInstRel.getTableName(), RelType.PROD_REL_TYPE,
                "");

            // 退订接入产品实例下的所有可选包销售品实例
            List<KiteOfferInst> additionalOfferInsts = querySceneInstService
                .listAdditionalOfferInstsFromProdInst(custId, prodInstId);
            dismantleAdditionalOfferInsts(orderRequest, additionalOfferInsts, custId, InstType.PROD_INST, prodInstId);
        }
    }

    /**
     * 接入产品实例拆机时把所有的子实例拉出来D掉
     * @param orderRequest
     * @param prodInst
     * @param kiteInsts
     * @param tableName
     */
    private void dismantleInsts(OrderRequest orderRequest, ProdInst prodInst, List<? extends KiteInst> kiteInsts,
        String tableName) {
        if (!ObjectUtils.allNotNull(orderRequest, prodInst)
            || !Objects.equals(ActionType.D.name(), prodInst.getActionType()) || CollectionUtils.isEmpty(kiteInsts)
            || StringUtils.isBlank(tableName)) {
            return;
        }

        String custId = prodInst.getOwnerCustId();
        String prodInstId = prodInst.getProdInstId();
        for (KiteInst kiteInst : kiteInsts) {
            IInstLoader<IInst> instLoader = InstLoaderFactory.getInstLoader(tableName);
            IInst inst = instLoader.loadInst(orderRequest, tableName, kiteInst.getInstId(), custId);
            InstConstructor.dismantleInst(orderRequest, inst, kiteInst.getInstType(), kiteInst.getInstId(),
                InstType.PROD_INST, prodInstId);
        }
    }

    /**
     * 删除关系实例
     * @param orderRequest
     * @param instRels
     * @param tableName
     * @param relType
     * @param custId
     */
    private void dismantleInstRels(OrderRequest orderRequest, List<KiteInstRelDTO> instRels, String tableName,
        String relType, String custId) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(instRels) || StringUtils.isBlank(tableName)) {
            return;
        }

        InstContainerProxy instContainer = InstContainer.ofRequest(orderRequest);
        for (KiteInstRelDTO instRel : instRels) {
            RelEdge relEdge = KiteBeanUtils.transform(instRel, RelEdge.class);
            relEdge.setSourceInstId(instRel.getaInstId());
            relEdge.setSourceInstType(instRel.getaInstType());
            relEdge.setTargetInstId(instRel.getzInstId());
            relEdge.setTargetInstType(instRel.getzInstType());

            if (Objects.equals(RelType.OFFER_OBJ_REL_TYPE_170000, instRel.getRelType())) {
                // 账户级销售品的objId是acctId
                KiteOfferInstAcct offerInstAcct = querySceneInstService.getOfferInstAcct(custId, instRel.getzInstId());
                if (Objects.nonNull(offerInstAcct)) {
                    relEdge.setTargetInstId(offerInstAcct.getAcctId());
                }
            }

            String relTypeCode = RelTypeUtils.getRelTypeCode(relEdge);
            IInst inst = instContainer.getInstRel(tableName, relEdge.getSourceInstId(), relEdge.getTargetInstId(),
                relTypeCode);
            if (Objects.isNull(inst)) {
                RelConstructor<IInst> relConstructor = DataConstructorFactory.getRelConstructor(relType);
                inst = relConstructor.getInstRel(relEdge.getSourceInstId(), relEdge.getTargetInstId(), relTypeCode,
                    custId);
                instContainer.addInst(inst);
            }

            RelConstructor.dismantleInstRel(orderRequest, inst, relEdge);
        }
    }

    /**
     * 基础销售品实例拆机
     * @param orderRequest
     * @param offerInst
     */
    private void dismantleBaseOfferInst(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)
            || !Objects.equals(CoreDataOffer.OFF_0005_10, offerInst.getOfferType())
            || !Objects.equals(ActionType.D.name(), offerInst.getActionType())) {
            return;
        }

        String custId = offerInst.getOwnerCustId();
        String offerInstId = offerInst.getOfferInstId();
        String offerType = offerInst.getOfferType();

        ProdInst prodInst = orderRequest.getInstContainer().getProdInstMap().get(offerInstId);
        String prodInstId = Optional.ofNullable(prodInst).map(ProdInst::getProdInstId).orElse("");

        // 补充基础销售品实例actionType=D的变动信息
        AcceptUtils.addInstChange(orderRequest, offerInstId, InstType.BASE_OFFER_INST, ActionType.D,
            KiteInst.ACTION_TYPE, ActionType.K.name(), ActionType.D.name());

        // 补充基础销售品实例明细actionType=D的变动信息
        AcceptUtils.addRelChange(orderRequest, offerInstId, InstType.BASE_OFFER_INST, prodInstId, InstType.PROD_INST,
            RelType.OFFER_OBJ_REL_TYPE_1000, KiteInst.ACTION_TYPE, ActionType.K.name(), ActionType.D.name());

        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(custId, InstType.PROD_INST,
            prodInstId, Lists.newArrayList(InstType.MAIN_OFFER_INST, InstType.PROMOTION_OFFER_INST,
                InstType.ADDITIONAL_OFFER_INST));

        // 删除基础销售品实例对应的接入产品实例与父级套餐销售品实例和促销包销售品实例的关系
        dismantleInstRels(orderRequest, instRels, TableConsts.OfferObjInstRel.getTableName(),
            RelType.OFFER_OBJ_REL_TYPE, custId);

        modifyParentOfferInsts(orderRequest, instRels, custId);

        // 基础销售品实例和功能产品实例关系
        dismantleOfferProdInstRels(orderRequest, offerInstId, offerType, custId);
    }

    /**
     * 删除销售品产品实例关系
     * @param orderRequest
     * @param offerInstId
     * @param offerType
     * @param custId
     */
    private void dismantleOfferProdInstRels(OrderRequest orderRequest, String offerInstId, String offerType,
        String custId) {
        if (Objects.isNull(orderRequest) || StringUtils.isAnyBlank(offerInstId, offerType, custId)) {
            return;
        }

        InstContainerProxy instContainer = InstContainer.ofRequest(orderRequest);
        List<OfferProdInstRel> offerProdInstRels = listOfferProdInstRels(offerInstId, custId);
        for (OfferProdInstRel offerProdInstRel : offerProdInstRels) {
            RelEdge relEdge = new RelEdge();
            relEdge.setSourceInstId(offerProdInstRel.getOfferInstId());
            relEdge.setSourceInstType(AcceptUtils.getOfferInstType(offerType));
            relEdge.setTargetInstId(offerProdInstRel.getProdInstId());
            relEdge.setTargetInstType(InstType.PROD_INST_FUNC);
            relEdge.setRelType(RelTypeUtils.getRelType(RelType.OFFER_PROD_REL_TYPE, offerProdInstRel.getRelType()));
            relEdge.setRoleId(offerProdInstRel.getRoleId());
            relEdge.setDetailId(offerProdInstRel.getDetailId());

            OfferProdInstRel instRel = instContainer.getOfferProdInstRel(offerProdInstRel.getOfferProdInstRelId());
            if (Objects.isNull(instRel)) {
                instContainer.addOfferProdInstRel(offerProdInstRel);
            }

            RelConstructor.dismantleInstRel(orderRequest, offerProdInstRel, relEdge);
        }
    }

    /**
     * 根据销售品实例id查询销售品产品实例关系
     * @param offerInstId
     * @param custId
     * @return
     */
    private List<OfferProdInstRel> listOfferProdInstRels(String offerInstId, String custId) {
        if (StringUtils.isAnyBlank(offerInstId, custId)) {
            return new ArrayList<>();
        }

        Example example = new Example(OfferProdInstRel.class);
        example.createCriteria().andEqualTo("offerInstId", offerInstId).andEqualTo("ownerCustId", custId);
        OfferProdInstRelMapper mapper = SpringUtil.getBean(OfferProdInstRelMapper.class);
        return mapper.selectByExample(example);
    }

    /**
     * 基础销售品实例退订后，如果父级销售品实例下没有有效的接入产品实例，则也退订父级销售品实例<br>
     * 如果父级销售品实例下还有有效的接入产品实例，并且actionType不为D，则把父级销售品实例的actionType改为M，seq + 1，增加实例变动
     * @param orderRequest
     * @param instRels
     * @param custId
     */
    private void modifyParentOfferInsts(OrderRequest orderRequest, List<KiteInstRelDTO> instRels, String custId) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(instRels)) {
            return;
        }

        for (KiteInstRelDTO instRel : instRels) {
            if (!AcceptUtils.isOfferInst(instRel.getaInstType())) {
                continue;
            }

            IInstLoader<OfferInst> instLoader = InstLoaderFactory.getInstLoader(TableConsts.OfferInst.getTableName());
            OfferInst offerInst = instLoader.loadInst(orderRequest, TableConsts.OfferInst.getTableName(),
                instRel.getaInstId(), custId);
            if (Objects.isNull(offerInst)) {
                continue;
            }

            if (!hasEffectiveProdInst(orderRequest, offerInst) || lessThanMinRole(orderRequest, offerInst)) {
                // 如果父级销售品实例下没有有效的接入产品实例，则也退订父级销售品实例
                dismantleOfferInst(orderRequest, offerInst);
            }
            else {
                if (Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())) {
                    // 如果是可选包销售品实例，还要修改上级销售品实例actionType
                    modifyParentOfferInstByAdditionalOfferInst(orderRequest, offerInst);
                }

                // 如果父级销售品实例下还有有效的接入产品实例，并且actionType不为D，则把父级销售品实例的actionType改为M，seq + 1，增加实例变动
                addSeqChange(orderRequest, offerInst);
            }
        }
    }

    /**
     * 判断销售品实例是否有有效接入产品实例
     * @param orderRequest
     * @param offerInst
     * @return
     */
    private boolean hasEffectiveProdInst(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)) {
            return false;
        }

        // 销售品实例和接入产品实例关系
        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByAInst(offerInst.getOwnerCustId(),
            InstTypeUtils.listOfferInstTypes(), offerInst.getOfferInstId(), InstType.PROD_INST);
        for (KiteInstRelDTO instRel : instRels) {
            String actionType = getOfferObjInstRelActionType(orderRequest, instRel);
            // 有有效的销售品明细实例
            if (!StringUtils.equalsAny(actionType, ActionType.D.name(), ActionType.X.name())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取获取销售品包含对象实例的actionType
     * @param orderRequest
     * @param instRel
     * @return
     */
    private String getOfferObjInstRelActionType(OrderRequest orderRequest, KiteInstRelDTO instRel) {
        String actionType = "";
        if (!ObjectUtils.allNotNull(orderRequest, instRel)) {
            return actionType;
        }

        String type = Optional.ofNullable(instRel.getRelType()).map(IRelType::getType).orElse("");
        String code = Optional.ofNullable(instRel.getRelType()).map(IRelType::getCode).orElse("");
        if (!Objects.equals(RelType.OFFER_OBJ_REL_TYPE, type)) {
            return actionType;
        }

        // 获取销售品包含对象实例
        OfferObjInstRel offerObjInstRel = InstContainer.ofRequest(orderRequest).getOfferObjInstRel(instRel.getaInstId(),
            instRel.getzInstId(), code);
        if (Objects.nonNull(offerObjInstRel)) {
            actionType = offerObjInstRel.getActionType();
        }
        else {
            actionType = ManagerUtils.getEnumName(instRel.getActionType());
        }

        return actionType;
    }

    /**
     * 判断销售品实例的有效明细实例是否小于配置中要求的最小值
     * @param orderRequest
     * @param offerInst
     * @return
     */
    private boolean lessThanMinRole(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)) {
            return false;
        }

        Offer offer = OfferCache.get(offerInst.getOfferId());
        if (Objects.isNull(offer)) {
            return false;
        }

        // 销售品实例和接入产品实例关系
        List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByAInst(offerInst.getOwnerCustId(),
            InstTypeUtils.listOfferInstTypes(), offerInst.getOfferInstId(), InstType.PROD_INST);
        List<OfferDetail> offerDetails = offer.listAccessProdDetail();
        for (OfferDetail offerDetail : offerDetails) {
            if (!Objects.equals(CoreDataPublic.PUB_C_0001_1000, offerDetail.getStatusCd())) {
                continue;
            }

            String roleId = offerDetail.getRoleId();
            String objId = offerDetail.getObjId();
            List<KiteInstRelDTO> effectiveInstRels = listEffectiveInstRels(orderRequest, instRels, roleId, objId);
            if (effectiveInstRels.size() < NumberUtils.toInt(offerDetail.getMinNum())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取相同角色id和相同规则id有效的关系实例
     * @param orderRequest
     * @param instRels
     * @param roleId
     * @param objId
     * @return
     */
    private List<KiteInstRelDTO> listEffectiveInstRels(OrderRequest orderRequest, List<KiteInstRelDTO> instRels,
        String roleId, String objId) {
        if (Objects.isNull(orderRequest) || CollectionUtils.isEmpty(instRels)) {
            return new ArrayList<>();
        }

        return instRels.stream().filter(instRel -> {
            if (Objects.equals(roleId, instRel.getRoleId()) && Objects.equals(objId, instRel.getzSpecId())) {
                String actionType = getOfferObjInstRelActionType(orderRequest, instRel);
                if (!StringUtils.equalsAny(actionType, ActionType.D.name(), ActionType.X.name())) {
                    return true;
                }
            }

            return false;
        }).collect(Collectors.toList());
    }

    /**
     * actionType改为M并补充seq的变动信息
     * @param orderRequest
     * @param offerInst
     */
    private void addSeqChange(OrderRequest orderRequest, OfferInst offerInst) {
        if (!ObjectUtils.allNotNull(orderRequest, offerInst)
            || Objects.equals(ActionType.D.name(), offerInst.getActionType()) || AcceptUtils.isAddInst(offerInst)) {
            return;
        }

        InstType instType = AcceptUtils.getOfferInstType(offerInst.getOfferType());
        KiteInstChange instChange = getInstChange(orderRequest, instType, offerInst.getOfferInstId(), "seq");
        if (Objects.nonNull(instChange)) {
            return;
        }

        if (StringUtils.equalsAny(offerInst.getActionType(), ActionType.A.name(), ActionType.K.name())) {
            AcceptUtils.setActionType(offerInst, ActionType.M.name());
        }

        // seq + 1
        int seq = NumberUtils.toInt(offerInst.getSeq(), 0);
        int newSeq = seq + 1;
        offerInst.setSeq(newSeq + "");

        // 补充seq的变动信息
        AcceptUtils.addInstChange(orderRequest, offerInst.getOfferInstId(), instType, ActionType.M, "seq", seq + "",
            newSeq + "");
    }

    /**
     * 根据fieldName获取变动信息
     * @param orderRequest
     * @param instType
     * @param instId
     * @param fieldName
     * @return
     */
    private KiteInstChange getInstChange(OrderRequest orderRequest, InstType instType, String instId, String fieldName) {
        if (!ObjectUtils.allNotNull(orderRequest, instType) || StringUtils.isAnyBlank(instId, fieldName)) {
            return null;
        }

        String key = ManagerUtils.join(instType, instId);
        List<KiteInstChange> instChanges = orderRequest.getInstChangeMap().getOrDefault(key, new ArrayList<>());
        for (KiteInstChange instChange : instChanges) {
            if (Objects.equals(instType, instChange.getSubInstType())
                && Objects.equals(instId, instChange.getSubInstId())
                && Objects.equals(fieldName, instChange.getFieldName())) {
                return instChange;
            }
        }

        return null;
    }
}
